package com.myown.web;


import com.myown.constant.ConstantInfo;
import com.myown.dto.json.JsonResult;
import com.myown.dto.json.StatusModel;
import com.myown.exception.*;
import com.myown.exception.enums.ExpectionEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @description 顶层异常捕获处理
 * @author lincky
 * @time 20:21 2016/12/8
 * @version v1.0.0
 */
@ControllerAdvice
public class CommonExceptionController extends BaseController {
    // 日志记录对象
    private final static Logger logger = LoggerFactory.getLogger(CommonExceptionController.class);

    /**
     * @description 捕获SystemInnerException
     * @author lincky
     * @time 00:39 2016.12.09
     * @method handleSystemInnerException
     * @param [request, e]
     * @return void
     * @version v1.0.0
     */
    @ExceptionHandler(SystemInnerException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public void handleSystemInnerException(HttpServletRequest request,
                                            SystemInnerException e) {
        handleLog(request, e);
        try {
            response.sendRedirect(ConstantInfo.Path.RELATIVE_PATH_404);
        } catch (IOException ignored) {
            // 404页面找不到将跳转web.xml404页面
        }
    }

    /**
     * @description 捕获NotFoundException，自动渲染页面
     * @author lincky
     * @time 00:40 2016.12.09
     * @method handleNotFoundException
     * @param [request, e]
     * @return void
     * @version v1.0.0
     */
    @ExceptionHandler(NotFoundException.class)
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ResponseBody
    public void handleNotFoundException(HttpServletRequest request,
                                                NotFoundException e) {
        try {
            response.sendRedirect(ConstantInfo.Path.RELATIVE_PATH_404);
        } catch (IOException ignored) {
            // 404页面找不到将跳转web.xml404页面
        }
    }

    /**
     * @description 捕获ServerRejectException
     * @author lincky
     * @time 00:40 2016.12.09
     * @method handleRejectedExecutionException
     * @param [request, e]
     * @return com.myown.dto.json.JsonResult
     * @version v1.0.0
     */
    @ExceptionHandler(ServerRejectException.class)
//    @ResponseStatus(value = HttpStatus.FORBIDDEN)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public JsonResult handleRejectedExecutionException(HttpServletRequest request,
                                            ServerRejectException e) {
        return getJsonResult(e);
    }

    /**
     * @description 捕获BadRequestException
     * @author lincky
     * @time 00:40 2016.12.09
     * @method handleBadRequestException
     * @param [request, e]
     * @return void
     * @version v1.0.0
     */
    @ExceptionHandler(BadRequestException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public void handleBadRequestException(HttpServletRequest request,
                                                          BadRequestException e) {
        try {
            response.sendRedirect(ConstantInfo.Path.RELATIVE_PATH_404);
        } catch (IOException ignored) {
            // 404页面找不到将跳转web.xml404页面
        }
    }

    /**
     * @description 捕获Exception
     * @author lincky
     * @time 00:40 2016.12.09
     * @method handleException
     * @param [request, e]
     * @return void
     * @version v1.0.0
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public void handleException(HttpServletRequest request,
                                      Exception e) {
        if (!(e instanceof HttpRequestMethodNotSupportedException)) {
            handleLog(request, e);
        }
        try {
            response.sendRedirect(ConstantInfo.Path.RELATIVE_PATH_404);
        } catch (IOException ignored) {
            // 404页面找不到将跳转web.xml404页面
        }
    }

    /**
     * @description 获取JsonResult对象
     * @author lincky
     * @time 00:41 2016.12.09
     * @method getJsonResult
     * @param [e]
     * @return com.myown.dto.json.JsonResult
     * @version v1.0.0
     */
    private JsonResult getJsonResult(CommonException e) {
        StatusModel StatusModel = new StatusModel();
        ExpectionEnum expectionEnum = e.getExpectionEnum();
        StatusModel.setExtralMessage(e.getExtralMessage());
        if (expectionEnum != null) {
            StatusModel.setCode(e.getCode());
            StatusModel.setMessage(e.getMessage());
        }
        return new JsonResult(StatusModel);
    }

    /**
     * @description 写入错误日志
     * @author lincky
     * @time 00:41 2016.12.09
     * @method handleLog
     * @param [request, e]
     * @return void
     * @version v1.0.0
     */
    private void handleLog(HttpServletRequest request, Exception e) {
        StringBuilder logBuilder = new StringBuilder();
        if (request != null) {
            logBuilder.append("url=").append(request.getRequestURL());
            logBuilder.append(" method=").append(request.getMethod());
            logBuilder.append(" parameter=").
                    append(request.getParameterMap());
        }
        if (e != null) {
            logBuilder.append(" exception:").append(e);
        }
        logger.error(logBuilder.toString());
    }

    /**
     * @description 返回404页面
     * @author lincky
     * @time 00:41 2016.12.09
     * @method get404ModelAndView
     * @param []
     * @return org.springframework.web.servlet.ModelAndView
     * @version v1.0.0
     */
    private ModelAndView get404ModelAndView() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("404");
        return modelAndView;
    }

}
